#include "Common.h"
#include <cassert>
#include <iomanip>
#include <iostream>
#include <set>
#include <string>

#if __has_include(<optional>)
static constexpr bool hasOptional = true;
#else
static constexpr bool hasOptional = false;
#endif

void structuredBindings()
{
    std::set<std::string> myset;
    if (auto [iter, success] = myset.insert("Hello"); success)
        std::cout << "Insert is successful. The value is " << std::quoted(*iter) << '\n';
    else
        std::cout << "The value " << std::quoted(*iter) << " already exists in the set\n";
}

namespace A::B::C {
int theVal = 100;
}

void nestedNamespaces()
{
    std::cout << "the value is: " << A::B::C::theVal << std::endl;
}

struct Struc {
    int val { 0 };
    void f()
    {
        int a = 1;
        std::cout << "default member value: " << val << std::endl;
        std::cout << "local value: " << a << std::endl;
        auto lam = [=, *this] {
            std::cout << "member value in lambda: " << (*this).val << std::endl;
            std::cout << "local value in lambda: " << a << std::endl;
        };
        a = 2;
        val = 3;
        std::cout << "member value changed to: " << val << std::endl;
        std::cout << "local value changed to: " << a << std::endl;
        lam();
    }
};

void captureThisInLambda()
{
    Struc a;
    a.f();
}

void constexprLambda()
{
    constexpr auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
    constexpr auto C = [](auto a) { return a; };
    static_assert(Fwd(C, 3) == 3);
}

void attrFallthrough()
{
    int val = 2;
    switch (val) {
    case 1:
        std::cout << "one ";
    case 2:
        std::cout << "two ";
        [[fallthrough]];
    case 3:
        std::cout << "three ";
    default:
        std::cout << "default ";
    }
    std::cout << std::endl;
}

struct [[nodiscard]] error_info {};
error_info enable_missile_safety_mode() { return error_info(); }

void attrNodiscard()
{
    enable_missile_safety_mode();
}

[[maybe_unused]] void f([[maybe_unused]] bool thing1,
    [[maybe_unused]] bool thing2)
{
    [[maybe_unused]] bool b = thing1 && thing2;
    assert(b); // in release mode, assert is compiled out, and b is unused
        // no warning because it is declared [[maybe_unused]]
} // parameters thing1 and thing2 are not used, no warning

void attrMaybeunused()
{
    f(1, 1);
}

void hasInclude()
{
    std::cout << "has header <optional>? " << (hasOptional ? "Yes" : "No") << std::endl;
}
